﻿using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Text;

namespace Pinwheel.Toolkits.Generator
{
    internal static class DiagnosticDescriptors
    {
        const string Category = "GenerateLSerializeCode";

        public static readonly DiagnosticDescriptor MustBePartial = new(
            id: "SERIALIZE001",
            title: "LSerializable object must be partial",
            messageFormat: "The LSerializable object '{0}' must be partial",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor NestedNotAllow = new(
            id: "SERIALIZE002",
            title: "LSerializable object must not be nested type",
            messageFormat: "The LSerializable object '{0}' must be not nested type",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor AbstractMustUnion = new(
            id: "SERIALIZE003",
            title: "abstract/interface type of LSerializable object must annotate with Union",
            messageFormat: "abstract/interface type of LSerializable object '{0}' must annotate with Union",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor MultipleCtorWithoutAttribute = new(
            id: "SERIALIZE004",
            title: "Require [LSerializeConstructor] when exists multiple constructors",
            messageFormat:
            "The LSerializable object '{0}' must annotate with [LSerializeConstructor] when exists multiple constructors",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor MultipleCtorAttribute = new(
            id: "SERIALIZE005",
            title: "[LSerializeConstructor] exists in multiple constructors",
            messageFormat: "Mupltiple [LSerializeConstructor] exists in '{0}' but allows only single ctor",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor ConstructorHasNoMatchedParameter = new(
            id: "SERIALIZE006",
            title: "LSerializeObject's constructor has no matched parameter",
            messageFormat:
            "The LSerializable object '{0}' constructor's parameter '{1}' must match a serialized member name(case-insensitive)",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor OnMethodHasParameter = new(
            id: "SERIALIZE007",
            title: "LSerializeObject's On*** methods must has no parameter",
            messageFormat: "The LSerializable object '{0}''s '{1}' method must has no parameter",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor OnMethodInUnamannagedType = new(
            id: "SERIALIZE008",
            title: "LSerializeObject's On*** methods can't annotate in unamnaged struct",
            messageFormat:
            "The LSerializable object '{0}' is unmanaged struct that can't annotate On***Attribute however '{1}' method annotaed",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor OverrideMemberCantAddAnnotation = new(
            id: "SERIALIZE009",
            title: "Override member can't annotate Ignore/Include attribute",
            messageFormat: "The LSerializable object '{0}' override member '{1}' can't annotate {2} attribute",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor SealedTypeCantBeUnion = new(
            id: "SERIALIZE010",
            title: "Sealed type can't be union",
            messageFormat: "The LSerializable object '{0}' is sealed type so can't be Union",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);


        public static readonly DiagnosticDescriptor ConcreteTypeCantBeUnion = new(
            id: "SERIALIZE011",
            title: "Concrete type can't be union",
            messageFormat: "The LSerializable object '{0}' can be Union, only allow abstract or interface",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);


        public static readonly DiagnosticDescriptor UnionTagDuplicate = new(
            id: "SERIALIZE012",
            title: "Union tag is duplicate",
            messageFormat: "The LSerializable object '{0}' union tag value is duplicate",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);


        public static readonly DiagnosticDescriptor UnionMemberTypeNotImplementBaseType = new(
            id: "SERIALIZE013",
            title: "Union member not implement union interface",
            messageFormat: "The LSerializable object '{0}' union member '{1}' not implement union interface",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);


        public static readonly DiagnosticDescriptor UnionMemberTypeNotDerivedBaseType = new(
            id: "SERIALIZE014",
            title: "Union member not dervided union base type",
            messageFormat: "The LSerializable object '{0}' union member '{1}' not derived union type",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor UnionMemberNotAllowStruct = new(
            id: "SERIALIZE015",
            title: "Union member can't be struct",
            messageFormat: "The LSerializable object '{0}' union member '{1}' can't be member, not allows struct",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor UnionMemberMustBeLSerializable = new(
            id: "SERIALIZE016",
            title: "Union member must be LSerializable",
            messageFormat: "The LSerializable object '{0}' union member '{1}' must be LSerializable",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor MembersCountOver250 = new(
            id: "SERIALIZE017",
            title: "Members count limit",
            messageFormat: "The LSerializable object '{0}' member count is '{1}', however limit size is 249",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor MemberCantSerializeType = new(
            id: "SERIALIZE018",
            title: "Member can't serialize type",
            messageFormat: "The LSerializable object '{0}' member '{1}' type is '{2}' that can't serialize",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor MemberIsNotLSerializable = new(
            id: "SERIALIZE019",
            title: "Member is not LSerializable object",
            messageFormat:
            "The LSerializable object '{0}' member '{1}' type '{2}' is not LSerializable. Annotate [LSerializable] to '{2}' or if external type that can serialize, annotate `[LSerializeAllowSerialize]` to member",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor TypeIsRefStruct = new(
            id: "SERIALIZE020",
            title: "Type is ref struct",
            messageFormat: "The LSerializable object '{0}' is ref struct, it can not serialize",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor MemberIsRefStruct = new(
            id: "SERIALIZE021",
            title: "Member is ref struct",
            messageFormat:
            "The LSerializable object '{0}' member '{1}' type '{2}' is ref struct, it can not serialize",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor CollectionGenerateIsAbstract = new(
            id: "SERIALIZE022",
            title: "Collection type not allows interface/abstract",
            messageFormat:
            "The LSerializable object '{0}' is GenerateType.Collection but interface/abstract, only allows concrete type",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor CollectionGenerateNotImplementedInterface = new(
            id: "SERIALIZE023",
            title: "Collection type must implement collection interface",
            messageFormat:
            "The LSerializable object '{0}' is GenerateType.Collection but not implemented collection interface(ICollection<T>/ISet<T>/IDictionary<TKey,TValue>)",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor CollectionGenerateNoParameterlessConstructor = new(
            id: "SERIALIZE024",
            title: "Collection type must require parameterless constructor",
            messageFormat:
            "The LSerializable object '{0}' is GenerateType.Collection but not exists parameterless constructor",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor AllMembersMustAnnotateOrder = new(
            id: "SERIALIZE025",
            title: "All members must annotate LSerializeOrder when SerializeLayout.Explicit",
            messageFormat: "The LSerializable object '{0}' member '{1}' is not annotated LSerializeOrder",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor AllMembersMustBeContinuousNumber = new(
            id: "SERIALIZE026",
            title: "All LSerializeOrder members must be continuous number from zero",
            messageFormat: "The LSerializable object '{0}' member '{1}' is not continuous number from zero",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor GenerateTypeScriptMustBeLSerializable = new(
            id: "SERIALIZE027",
            title: "GenerateTypeScript must be LSerializable",
            messageFormat: "Type '{0}' is annotated GenerateTypeScript but not annotated LSerializable",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor GenerateTypeScriptOnlyAllowsGenerateTypeObject = new(
            id: "SERIALIZE028",
            title: "GenerateTypeScript must be LSerializable(GenerateType.Object)",
            messageFormat:
            "Type '{0}' is annotated GenerateTypeScript, its LSerializable only allows GenerateType.Object",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor GenerateTypeScriptDoesNotAllowGenerics = new(
            id: "SERIALIZE029",
            title: "GenerateTypeScript type does not allow generics",
            messageFormat: "Type '{0}' is annotated GenerateTypeScript that does not allow generics parameter",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor GenerateTypeScriptDoesNotAllowLongEnum = new(
            id: "SERIALIZE030",
            title: "GenerateTypeScript type does not allow 64bit enum",
            messageFormat:
            "GenerateTypeScript type '{0}' has not support 64bit(long/ulong) enum type '{1}', 64bit enum is not supported in typescript generation",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor GenerateTypeScriptNotSupportedType = new(
            id: "SERIALIZE031",
            title: "not allow GenerateTypeScript type",
            messageFormat:
            "GenerateTypeScript type '{0}' member '{1}' type '{2}' is not supported type in typescript generation",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor GenerateTypeScriptNotSupportedCustomFormatter = new(
            id: "SERIALIZE032",
            title: "not allow GenerateTypeScript type",
            messageFormat:
            "GenerateTypeScript type '{0}' member '{1}' is annnotated [LSerializeCustomFormatter] that not supported in typescript generation",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor CircularReferenceOnlyAllowsParameterlessConstructor = new(
            id: "SERIALIZE033",
            title: "CircularReference LSerialize Object must require parameterless constructor",
            messageFormat:
            "The LSerializable object '{0}' is GenerateType.CircularReference but not exists parameterless constructor.",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor UnamangedStructWithLayoutAutoField = new(
            id: "SERIALIZE034",
            title: "Before .NET 7 unmanaged struct must annotate LayoutKind.Auto or Explicit",
            messageFormat:
            "The unmanaged struct '{0}' has LayoutKind.Auto field('{1}'). Before .NET 7, if field contains Auto then automatically promote to LayoutKind.Auto but .NET 7 is Sequential so breaking binary compatibility when runtime upgraded. To safety, you have to annotate [StructLayout(LayoutKind.Auto)] or LayoutKind.Explicit to type.",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor UnamangedStructLSerializeCtor = new(
            id: "SERIALIZE035",
            title: "Unamanged strcut does not allow [LSerializeConstructor]",
            messageFormat:
            "The unamanged struct '{0}' can not annotate with [LSerializeConstructor] because don't call any constructors",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor InheritTypeCanNotIncludeParentPrivateMember = new(
            id: "SERIALIZE036",
            title: "Inherit type can not include private member",
            messageFormat: "Type '{0}' can not include parent type's private member '{1}'",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor ReadOnlyFieldMustBeConstructorMember = new(
            id: "SERIALIZE037",
            title: "Readonly field must be constructor member",
            messageFormat: "Type '{0}' readonly field '{1}' must be constructor member",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);

        public static readonly DiagnosticDescriptor DuplicateOrderDoesNotAllow = new(
            id: "SERIALIZE038",
            title: "All members order must be unique",
            messageFormat: "The LSerializable object '{0}' member '{1}' is duplicated order between '{2}'.",
            category: Category,
            defaultSeverity: DiagnosticSeverity.Error,
            isEnabledByDefault: true);
    }
}